﻿using System.Collections.Generic;
using System.Linq;
using Basmus.Conel;

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace Basmus.Tests
{
    [TestClass()]
    public class CollectionBinderTest
    {
        private TestContext testContextInstance;
        
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Дополнительные атрибуты теста
        // 
        //При написании тестов можно использовать следующие дополнительные атрибуты:
        //
        //ClassInitialize используется для выполнения кода до запуска первого теста в классе
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //ClassCleanup используется для выполнения кода после завершения работы всех тестов в классе
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //TestInitialize используется для выполнения кода перед запуском каждого теста
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //TestCleanup используется для выполнения кода после завершения каждого теста
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion

        private static IEnumerable<Type> GetBindingListContainerTypes(Type elementType)
        {
            return new[] { typeof(List<>), typeof(IList<>) }
                .MakeGenericTypesForArguments(elementType);
        }

        private static IEnumerable<Type> GetArrayBindingContainerTypes(Type elementType)
        {
            return new[]
                       {
                           typeof (IEnumerable<>).MakeGenericType(elementType),
                           elementType.MakeArrayType()
                       };
        }

       
        [TestMethod()]
        public void ListBindingTest()
        {
            //Arrange
            var target = new CollectionBinder();

            //Arrange & Act & Assert
            foreach (var elementType in TypeHelper.EveryPossibleElementTypes())
            {
                var containerTypes = GetBindingListContainerTypes(elementType);
                foreach (var containerType in containerTypes)
                {
                    //Arrage
                    var expectedBindingType = typeof (ListBinding<>).MakeGenericType(elementType);

                    //Act
                    var binding = target.Bind(containerType);

                    //Assert
                    Assert.IsNotNull(binding);
                    Assert.IsInstanceOfType(binding, expectedBindingType);

                    //Act
                    binding = target.Bind(containerType, elementType);

                    //Assert
                    Assert.IsNotNull(binding);
                    Assert.IsInstanceOfType(binding, expectedBindingType);
                }
            }
        }

        [TestMethod()]
        public void ArrayBindingTest()
        {
            //Arrange
            var target = new CollectionBinder();

            //Arrange & Act & Assert
            foreach (var elementType in TypeHelper.EveryPossibleElementTypes())
            {
                var containerTypes = GetArrayBindingContainerTypes(elementType);
                foreach (var containerType in containerTypes)
                {
                    //Arrage
                    var expectedBindingType = typeof(ArrayBinding<>).MakeGenericType(elementType);

                    //Act
                    var binding = target.Bind(containerType);

                    //Assert
                    Assert.IsNotNull(binding);
                    Assert.IsInstanceOfType(binding, expectedBindingType);

                    //Act
                    binding = target.Bind(containerType, elementType);

                    //Assert
                    Assert.IsNotNull(binding);
                    Assert.IsInstanceOfType(binding, expectedBindingType);
                }
            }
        }

        [TestMethod()]
        public void NullForConatinerTypeTest()
        {
            //Arrange & Act & Assert
            var target = new CollectionBinder();
            
            var notNullContainerTypes = TypeHelper
                .EveryPossibleElementTypes()
                .SelectMany(elementType => GetArrayBindingContainerTypes(elementType)
                                               .Concat(GetBindingListContainerTypes(elementType)));
            var nullContainerTypes = TypeHelper
                .EveryPossibleContainerType()
                .Except(notNullContainerTypes);
            foreach (var containerType in nullContainerTypes)
            {
                //Act
                var binding = target.Bind(containerType);

                //Assert
                Assert.IsNull(binding);
            }
        }

        [TestMethod()]
        public void NullForConatinerTypeAndElementTypeTest()
        {
            //Arrange & Act & Assert
            var target = new CollectionBinder();
            var elementTypes = TypeHelper.EveryPossibleElementTypes();

            foreach (var elementType in elementTypes)
            {
                var notNullContainerTypes = GetArrayBindingContainerTypes(elementType)
                    .Concat(GetBindingListContainerTypes(elementType));
                var nullContainerTypes = TypeHelper
                    .EveryPossibleContainerType()
                    .Except(notNullContainerTypes);
                foreach (var containerType in nullContainerTypes)
                {
                    //Act
                    var binding = target.Bind(containerType, elementType);

                    //Assert
                    Assert.IsNull(binding);
                }
            }
        }
    }
}
